/* 
 * File:   FilterLines.cpp
 * Author: Guilherme Monteiro
 */

#include "../headers/FilterLines.h"

FilterLines::FilterLines(ROI* roi) {
    this->roi = roi;
}

FilterLines::FilterLines(const FilterLines& orig) {
}

FilterLines::~FilterLines() {
}

/**
 * Filter the lines detected and passed
 * in skeleton format (binarized format).
 * 
 * obs.: binarized format: 1=have a point there, 0=don't have a point there
 * 
 * @param lines
 * @return skeleton of lines filtered
 */
vector<Line> FilterLines::primaryFilter(vector<Line> linesDetected) {
    vector<Line> linesFiltered;

    //    vector<Line> lines;
    //    for(int i = 0; i < linesDetected.size()-1; i++) {
    //        CvPoint p1 = linesDetected.at(i);
    //        CvPoint p2 = linesDetected.at(++i);
    //        lines.push_back(Line(p1, p2));
    //    }

    vector<Line> vecAux;
    vector<Line>::iterator itAux;
    vector<Line>::iterator itLines;
    for (itLines = linesDetected.begin(); itLines != linesDetected.end(); itLines++) {
        CvPoint p1 = (*itLines).p1, p2 = (*itLines).p2;
        if (p1.x == -1 && p1.y == -1 && p2.x == -1 && p2.y == -1) {
            if (vecAux.size() != 0) {
                int i = 0;
                for (itAux = vecAux.begin(); itAux != vecAux.end(); itAux++, i++) {
                    if (i != floor(vecAux.size() / 2)) { // while don't be the middle line
                        linesFiltered.push_back(Line(cvPoint(-1, -1), cvPoint(-1, -1)));
                    } else {
                        if (validatesLine(*itAux)) {
                            linesFiltered.push_back(*itAux);
                        }
                    }
                }
                vecAux.clear();
            }
            linesFiltered.push_back(*itLines);
        } else if (p1.x != -1 && p1.y != -1 && p2.x != -1 && p2.y != -1) {
            vecAux.push_back(*itLines);
        } else if (p1.x == -1 && p1.y == -1 && p2.x != -1 && p2.y != -1) {
            itLines++;
        } else if (p1.x != -1 && p1.y != -1 && p2.x == -1 && p2.y == -1) {
            itLines++;
        }
    }

    vector<Line> validLines;
    vector<Line>::iterator itFiltered;
    for (itFiltered = linesFiltered.begin(); itFiltered != linesFiltered.end(); itFiltered++) {
        if ((*itFiltered).p1.x != -1 && (*itFiltered).p1.y != -1) {
            validLines.push_back(Line((*itFiltered).p1, (*itFiltered).p2));
        }
    }

    //    for(int k = 0; k < validLines.size(); k++) {
    //        printf("validLines: (%d,%d)-(%d,%d)\n", 
    //                validLines[k].p1.x,
    //                validLines[k].p1.y,
    //                validLines[k].p2.x,
    //                validLines[k].p2.y);
    //    }

    //    printf("validLines.size: %d\n", (int)validLines.size());

    return validLines;
}

/**
 * Validates a line if it
 * is into roi delimited for
 * left upper and right bottom
 * points.
 * 
 * @param line
 * @param r
 * @return true if line is valid 
 */
bool FilterLines::validatesLine(Line line) {
    if (line.p1.x < 0 || line.p1.x > this->roi->getRightBottom().x - this->roi->getLeftUpper().x ||
            line.p1.y < 0 || line.p1.y > this->roi->getRightBottom().y - this->roi->getLeftUpper().y ||
            line.p2.x < 0 || line.p2.x > this->roi->getRightBottom().x - this->roi->getLeftUpper().x ||
            line.p2.y < 0 || line.p2.y > this->roi->getRightBottom().y - this->roi->getLeftUpper().y)
        return false;
    return true;
}

/**
 * Filter the lines based on minimum x-distance, to vertical lines,
 * and minimum y-distance, to horizontal lines.
 * 
 * @param validLines: vector of lines, filtered the invalid (-1,-1)-(-1,-1) lines
 * @return vector of lines filtered
 */
vector<Line> FilterLines::secondaryFilter(vector<Line> validLines) {
    vector<Line> result;
    Line previousLine, currentLine, nextLine;
    vector<Line>::iterator it;
    for (it = validLines.begin() + 1; (it + 1) != validLines.end(); it++) {
        previousLine = *(it - 1);
        currentLine = *it;
        nextLine = *(it + 1);

        if (currentLine.isHorizontal()) {
            if (previousLine.equals(this->roi->getUpLineTable())) {
                result.push_back(previousLine);
            }
            if (nextLine.equals(this->roi->getDownLineTable())) {
                result.push_back(nextLine);
            }

            if ((nextLine.p1.y - currentLine.p1.y) >= MIN_VERTICAL_DISTANCE &&
                    (nextLine.p2.y - currentLine.p2.y) >= MIN_VERTICAL_DISTANCE &&
                    (currentLine.p1.y - previousLine.p1.y) >= MIN_VERTICAL_DISTANCE &&
                    (currentLine.p2.y - previousLine.p2.y) >= MIN_VERTICAL_DISTANCE) {
                result.push_back(currentLine);
            }
        } 
        else {
            if (previousLine.equals(this->roi->getLeftLineTable())) {
                result.push_back(previousLine);
            }
            if (nextLine.equals(this->roi->getRightLineTable())) {
                result.push_back(nextLine);
            }

            if ((nextLine.p1.x - currentLine.p1.x) >= MIN_HORIZONTAL_DISTANCE &&
                    (nextLine.p2.x - currentLine.p2.x) >= MIN_HORIZONTAL_DISTANCE &&
                    (currentLine.p1.x - previousLine.p1.x) >= MIN_HORIZONTAL_DISTANCE &&
                    (currentLine.p2.x - previousLine.p2.x) >= MIN_HORIZONTAL_DISTANCE) {
                result.push_back(currentLine);
            }
        }
    }

    return result;
}